﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ITAP.ShprossesBuilder.Editor;
using ITAP.ShprossesBuilder.Modelling.Components;
using ITAP.ShprossesBuilder.Modelling;
using ITAP.ShprossesBuilder.Calculations;
using ITAP.ShprossesBuilder.Properties;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder.Operations
{
    public enum OffsetTo
    {
        Right, 
        Up, 
        Left, 
        Down, 
        None
    }

    public class OperationMoveComponentsWithOffset : IOperation
    {
        private ModelControl modelControl;
        private OffsetTo offset;

        public OperationMoveComponentsWithOffset()
        {
            this.offset = OffsetTo.None;
        }

        public OperationMoveComponentsWithOffset(bool canUndo, OffsetTo offset)
        {
            this.offset = offset;
            this.canUndo = canUndo;
        }
        #region IOperation Members

        public string Name
        {
            get { return "Смещение компонентов"; }
        }

        public OperationGroup OperationGroup
        {
            get { return OperationGroup.Other; }
        }

        public System.Drawing.Image Thumbnail
        {
            get { return Resources.MoveWithOffset.ToBitmap(); }
        }

        public void Execute(ModelControl modelControl)
        {
            this.modelControl = modelControl;
            if (this.offset == OffsetTo.None)
            {
               
                ContextMenuStrip menuStrip = new ContextMenuStrip();

                EventHandler handler = new EventHandler(OnItemClick);
                ToolStripItem right = new ToolStripMenuItem("Вправо", null, handler);
                right.Tag = OffsetTo.Right;
                menuStrip.Items.Add(right);
                ToolStripItem up = new ToolStripMenuItem("Вверх", null, handler);
                up.Tag = OffsetTo.Up;
                menuStrip.Items.Add(up);
                ToolStripItem left = new ToolStripMenuItem("Влево", null, handler);
                left.Tag = OffsetTo.Left;
                menuStrip.Items.Add(left);
                ToolStripItem down = new ToolStripMenuItem("Вниз", null, handler);
                down.Tag = OffsetTo.Down;
                menuStrip.Items.Add(down);

                menuStrip.Show(Cursor.Position);
            }
            else
                this.MoveWithOffset(this.offset, 1, false);
        }
        private bool canUndo = true;
        public bool CanUndo
        {
            get { return canUndo; }
        }

        #endregion

        private void MoveWithOffset(OffsetTo offset, double offsetValue, bool withCopy)
        {
            //bool isSomeComponentsNotMoved = false;
            IComponent component = null;
            foreach (IComponent selectedComponent in this.modelControl.ModelContainer.SelectedComponentsStack)
            {
                if (selectedComponent.Parent == null)
                    continue;

                if (selectedComponent is Shpross || selectedComponent is ShprossConnector)
                {
                    if (withCopy)
                    {
                        component = selectedComponent.Copy();
                        component.SerialNumber = 0;
                    }
                    else
                        component = selectedComponent;

                    if (component is Shpross)
                    {
                        Shpross shpross = component as Shpross;
                        if (shpross.SelectedPoint != ShprossPoints.Start && shpross.SelectedPoint != ShprossPoints.End && shpross.SelectedPoint != ShprossPoints.Center)
                            continue;
                        ModelPoint moveTo = this.GetMoveToPoint(shpross.SelectedPointPosition, offset, (int)offsetValue);
                        if (shpross.SelectedPoint == ShprossPoints.Start)
                            shpross.MoveStartPointTo(moveTo, selectedComponent.Parent.BoundingBox, false);
                        else if (shpross.SelectedPoint == ShprossPoints.End)
                            shpross.MoveEndPointTo(moveTo, selectedComponent.Parent.BoundingBox, false);
                        else if (shpross.SelectedPoint == ShprossPoints.Center)
                            shpross.MoveTo(moveTo, selectedComponent.Parent.BoundingBox);
                    }
                    if (component is ShprossConnector)
                    {
                        ShprossConnector connector = component as ShprossConnector;
                        ModelPoint moveTo = this.GetMoveToPoint(connector.Position, offset, (int)offsetValue);
                        connector.MoveTo(moveTo, selectedComponent.Parent.BoundingBox);
                    }
                    selectedComponent.Parent.AddInnerComponent(component);
                    component.Update();
                }
            }
            this.modelControl.UpdateModel();
        }

        private void OnItemClick(object sender, EventArgs e)
        {
            ToolStripMenuItem item = sender as ToolStripMenuItem;
            OffsetTo offset = (OffsetTo)item.Tag;
            MoveWithOffsetForm moveForm = new MoveWithOffsetForm("Смещение компонентов");
            if (moveForm.ShowDialog() != DialogResult.OK)
                return;

            this.MoveWithOffset(offset, moveForm.Offset, moveForm.OffsetWithCopy);
        }

        private ModelPoint GetMoveToPoint(ModelPoint source, OffsetTo offset, int offsetValue)
        {
            ModelVector vector = null;
            switch (offset)
            {
                case OffsetTo.Right:
                    vector = new ModelVector(offsetValue, 0);
                    break;
                case OffsetTo.Up:
                    vector = new ModelVector(0, offsetValue);
                    break;
                case OffsetTo.Left:
                    vector = new ModelVector(-offsetValue, 0);
                    break;
                case OffsetTo.Down:
                    vector = new ModelVector(0, -offsetValue);
                    break;
            }
            ModelPoint result = ModelCalculations.GetOffsetPoint(source, vector);
            return result;
        }
    }
}
